﻿using System;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Xrm.Sdk;
using Microsoft.Crm.Sdk;
using XrmLibrary.Adapters;
using XrmLibrary.MsCrm4Adapter.Connections;
using XrmLibrary.MsCrm4Adapter.Extensions;

namespace XrmLibrary.MsCrm4Adapter.Adapters
{
    public sealed class OrganizationServiceAdapter :  IOrganizationServiceAdapter
    {
        private readonly CrmService _crmServiceProxy;

        private OrganizationServiceAdapter(CrmService crmService)
        {
            _crmServiceProxy = crmService;
        }

        public static OrganizationServiceAdapter Instantiate(String crmServerUrl, String crmOrganizationName)
        {
            CrmService crmService = CrmServiceUtility.GetCrmService(crmServerUrl, crmOrganizationName);
            return new OrganizationServiceAdapter(crmService);
        }

        public Guid Create(Entity entity)
        {
            DynamicEntity dynamicEntity = entity.ToDynamicEntity();
            return _crmServiceProxy.Create(dynamicEntity);
        }

        public Entity Retrieve(string entityName, Guid id, ColumnSet columnSet)
        {
            Microsoft.Crm.Sdk.Query.ColumnSetBase columnSet4 = columnSet.ToColumnSet4();
            DynamicEntity dynamicEntity = (DynamicEntity)_crmServiceProxy.Retrieve(entityName, id, columnSet4);
            return dynamicEntity.ToEntity();
        }

        public void Update(Entity entity)
        {
            DynamicEntity dynamicEntity = entity.ToDynamicEntity();
            _crmServiceProxy.Update(dynamicEntity);
        }

        public void Delete(string entityName, Guid id)
        {
            _crmServiceProxy.Delete(entityName, id);
        }

        public OrganizationResponse Execute(OrganizationRequest request)
        {
            Request crm4Request = request.ToSdkTypeProxyRequest();
            Response crm4Response = _crmServiceProxy.Execute(crm4Request);
            return crm4Response.ToOrganizationResponse();
        }

        public void Associate(string entityName, Guid entityId, Relationship relationship, EntityReferenceCollection relatedEntities)
        {
            foreach (EntityReference t in relatedEntities)
            {
                AssociateEntitiesRequest request = new AssociateEntitiesRequest
                                                       {
                                                           Moniker1 = new Moniker {Id = entityId, Name = entityName},
                                                           Moniker2 = t.ToCrm4Moniker(),
                                                           RelationshipName = relationship.SchemaName
                                                       };

                // Execute
                _crmServiceProxy.Execute(request);
            }
        }

        public void Disassociate(string entityName, Guid entityId, Relationship relationship, EntityReferenceCollection relatedEntities)
        {
            foreach (EntityReference t in relatedEntities)
            {
                DisassociateEntitiesRequest request = new DisassociateEntitiesRequest
                                                          {
                                                              Moniker1 = new Moniker {Id = entityId, Name = entityName},
                                                              Moniker2 = t.ToCrm4Moniker(),
                                                              RelationshipName = relationship.SchemaName
                                                          };
                // Execute
                _crmServiceProxy.Execute(request);
            }
        }

        public EntityCollection RetrieveMultiple(QueryBase query)
        {
            BusinessEntityCollection businessEntityCollection = _crmServiceProxy.RetrieveMultiple(query.ToCrm4QueryExpression());
            return businessEntityCollection.ToEntityCollection();
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        /// <filterpriority>2</filterpriority>
        public void Dispose()
        {
            // This is only IDisposable to match the signature of the CRM 2011 service references.
        }
    }
}
